home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / app / tile_swap.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-11-22  |  19.4 KB  |  915 lines

  1. #include "config.h"
  2.  
  3. #include <glib.h>
  4.  
  5. #include <errno.h>
  6. #include <string.h>
  7. #include <stdio.h>
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #include <fcntl.h>
  11. #ifdef HAVE_UNISTD_H
  12. #include <unistd.h>
  13. #endif
  14. #ifdef USE_PTHREADS
  15. #include <pthread.h>
  16. #endif
  17.  
  18. #ifdef G_OS_WIN32
  19. #include <io.h>
  20. #endif
  21.  
  22. #ifndef _O_BINARY
  23. #define _O_BINARY 0
  24. #endif
  25. #ifndef _O_TEMPORARY
  26. #define _O_TEMPORARY 0
  27. #endif
  28.  
  29. #define MAX_OPEN_SWAP_FILES  16
  30.  
  31. #include "tile.h"
  32. #include "tile_swap.h"
  33. #include "tile_pvt.h"            /* ick. */
  34.  
  35. #include "libgimp/gimpintl.h"
  36.  
  37.  
  38. typedef struct _SwapFile      SwapFile;
  39. typedef struct _DefSwapFile   DefSwapFile;
  40. typedef struct _Gap           Gap;
  41. typedef struct _AsyncSwapArgs AsyncSwapArgs;
  42.  
  43. struct _SwapFile
  44. {
  45.   char *filename;
  46.   int swap_num;
  47.   SwapFunc swap_func;
  48.   gpointer user_data;
  49.   int fd;
  50. };
  51.  
  52. struct _DefSwapFile
  53. {
  54.   GList *gaps;
  55.   long swap_file_end;
  56.   off_t cur_position;
  57. };
  58.  
  59. struct _Gap
  60. {
  61.   long start;
  62.   long end;
  63. };
  64.  
  65. struct _AsyncSwapArgs
  66. {
  67.   DefSwapFile *def_swap_file;
  68.   int          fd;
  69.   Tile        *tile;
  70. };
  71.  
  72.  
  73. static void  tile_swap_init    (void);
  74. static guint tile_swap_hash    (int      *key);
  75. static gint  tile_swap_compare (int      *a,
  76.                 int      *b);
  77. static void  tile_swap_command (Tile     *tile,
  78.                 int       command);
  79. static void  tile_swap_open    (SwapFile *swap_file);
  80.  
  81. static int   tile_swap_default        (int       fd,
  82.                        Tile     *tile,
  83.                        int       cmd,
  84.                        gpointer  user_data);
  85. static void  tile_swap_default_in     (DefSwapFile *def_swap_file,
  86.                        int          fd,
  87.                        Tile        *tile);
  88. static void  tile_swap_default_in_async (DefSwapFile *def_swap_file,
  89.                         int          fd,
  90.                         Tile        *tile);
  91. static void  tile_swap_default_out    (DefSwapFile *def_swap_file,
  92.                        int          fd,
  93.                        Tile        *tile);
  94. static void  tile_swap_default_delete (DefSwapFile *def_swap_file,
  95.                        int          fd,
  96.                        Tile        *tile);
  97. static long  tile_swap_find_offset    (DefSwapFile *def_swap_file,
  98.                        int          fd,
  99.                        int          bytes);
  100. static void  tile_swap_resize         (DefSwapFile *def_swap_file,
  101.                        int          fd,
  102.                        long         new_size);
  103. static Gap*  tile_swap_gap_new        (long         start,
  104.                        long         end);
  105. static void  tile_swap_gap_destroy    (Gap         *gap);
  106. #ifdef USE_PTHREADS
  107. static void* tile_swap_in_thread      (void *);
  108. #endif
  109.  
  110.  
  111. static int initialize = TRUE;
  112. static GHashTable *swap_files = NULL;
  113. static GList *open_swap_files = NULL;
  114. static int nopen_swap_files = 0;
  115. static int next_swap_num = 1;
  116. static long swap_file_grow = 16 * TILE_WIDTH * TILE_HEIGHT * 4;
  117. #ifdef USE_PTHREADS
  118. static pthread_mutex_t swapfile_mutex = PTHREAD_MUTEX_INITIALIZER;
  119.  
  120. /* async_swapin_mutex protects only the list, not the tiles therein */
  121. static pthread_t swapin_thread;
  122. static pthread_mutex_t async_swapin_mutex = PTHREAD_MUTEX_INITIALIZER;
  123. static pthread_cond_t async_swapin_signal = PTHREAD_COND_INITIALIZER;
  124. static GSList *async_swapin_tiles = NULL;
  125. static GSList *async_swapin_tiles_end = NULL;
  126. #endif
  127.  
  128. static gboolean seek_err_msg = TRUE, read_err_msg = TRUE, write_err_msg = TRUE;
  129.  
  130. static void
  131. tile_swap_print_gaps (DefSwapFile *def_swap_file)
  132. {
  133.   GList *gaps;
  134.   Gap *gap;
  135.  
  136.   gaps = def_swap_file->gaps;
  137.   while (gaps)
  138.     {
  139.       gap = gaps->data;
  140.       gaps = gaps->next;
  141.  
  142.       g_print ("  %6ld - %6ld\n", gap->start, gap->end);
  143.     }
  144. }
  145.  
  146. static void
  147. tile_swap_exit1 (gpointer key,
  148.          gpointer value,
  149.          gpointer data)
  150. {
  151.   extern int tile_ref_count;
  152.   SwapFile *swap_file;
  153.   DefSwapFile *def_swap_file;
  154.  
  155.   if (tile_ref_count != 0)
  156.     g_warning ("tile ref count balance: %d\n", tile_ref_count);
  157.  
  158.   swap_file = value;
  159.   if (swap_file->swap_func == tile_swap_default)
  160.     {
  161.       def_swap_file = swap_file->user_data;
  162.       if (def_swap_file->swap_file_end != 0)
  163.     {
  164.       g_warning ("swap file not empty: \"%s\"\n", swap_file->filename);
  165.       tile_swap_print_gaps (def_swap_file);
  166.     }
  167.  
  168. #if defined (__EMX__) || defined (G_OS_WIN32)
  169.       /* should close before unlink */
  170.       if (swap_file->fd > 0)
  171.     {
  172.       close (swap_file->fd);
  173.       swap_file->fd = -1;
  174.     }
  175. #endif
  176.       unlink (swap_file->filename);
  177.     }
  178. }
  179.  
  180.  
  181. void
  182. tile_swap_exit ()
  183. {
  184. #ifdef HINTS_SANITY
  185.   extern int tile_exist_peak;
  186.  
  187.   fprintf(stderr,"Tile exist peak was %d Tile structs (%d bytes)",
  188.        tile_exist_peak, tile_exist_peak * sizeof(Tile));
  189. #endif
  190.  
  191.   if (swap_files)
  192.     g_hash_table_foreach (swap_files, tile_swap_exit1, NULL);
  193. }
  194.  
  195. int
  196. tile_swap_add (char     *filename,
  197.            SwapFunc  swap_func,
  198.            gpointer  user_data)
  199. {
  200.   SwapFile *swap_file;
  201.   DefSwapFile *def_swap_file;
  202.  
  203. #ifdef USE_PTHREADS
  204.   pthread_mutex_lock(&swapfile_mutex);
  205. #endif
  206.  
  207.   if (initialize)
  208.     tile_swap_init ();
  209.  
  210.   swap_file = g_new (SwapFile, 1);
  211.   swap_file->filename = g_strdup (filename);
  212.   swap_file->swap_num = next_swap_num++;
  213.  
  214.   if (!swap_func)
  215.     {
  216.       swap_func = tile_swap_default;
  217.  
  218.       def_swap_file = g_new (DefSwapFile, 1);
  219.       def_swap_file->gaps = NULL;
  220.       def_swap_file->swap_file_end = 0;
  221.       def_swap_file->cur_position = 0;
  222.  
  223.       user_data = def_swap_file;
  224.     }
  225.  
  226.   swap_file->swap_func = swap_func;
  227.   swap_file->user_data = user_data;
  228.   swap_file->fd = -1;
  229.  
  230.   g_hash_table_insert (swap_files, &swap_file->swap_num, swap_file);
  231.  
  232. #ifdef USE_PTHREADS
  233.   pthread_mutex_unlock(&swapfile_mutex);
  234. #endif
  235.   return swap_file->swap_num;
  236. }
  237.  
  238. void
  239. tile_swap_remove (int swap_num)
  240. {
  241.   SwapFile *swap_file;
  242.  
  243. #ifdef USE_PTHREADS
  244.   pthread_mutex_lock(&swapfile_mutex);
  245. #endif
  246.  
  247.   if (initialize)
  248.     tile_swap_init ();
  249.  
  250.   swap_file = g_hash_table_lookup (swap_files, &swap_num);
  251.   if (!swap_file)
  252.     goto out;
  253.  
  254.   g_hash_table_remove (swap_files, &swap_num);
  255.  
  256.   if (swap_file->fd != -1)
  257.     close (swap_file->fd);
  258.  
  259.   g_free (swap_file);
  260. out:
  261. #ifdef USE_PTHREADS
  262.   pthread_mutex_unlock(&swapfile_mutex);
  263. #endif
  264.   return;
  265. }
  266.  
  267. void
  268. tile_swap_in_async (Tile *tile)
  269. {
  270.   if (tile->swap_offset == -1)
  271.     return;
  272.  
  273.   tile_swap_command (tile, SWAP_IN_ASYNC);
  274. }
  275.  
  276. void
  277. tile_swap_in (Tile *tile)
  278. {
  279.   if (tile->swap_offset == -1)
  280.     {
  281.       tile_alloc (tile);
  282.       return;
  283.     }
  284.  
  285.   tile_swap_command (tile, SWAP_IN);
  286. }
  287.  
  288. void
  289. tile_swap_out (Tile *tile)
  290. {
  291.   tile_swap_command (tile, SWAP_OUT);
  292. }
  293.  
  294. void
  295. tile_swap_delete (Tile *tile)
  296. {
  297.   tile_swap_command (tile, SWAP_DELETE);
  298. }
  299.  
  300. void
  301. tile_swap_compress (int swap_num)
  302. {
  303.   tile_swap_command (NULL, SWAP_COMPRESS);
  304. }
  305.  
  306. gboolean
  307. tile_swap_test ()
  308. {
  309.   SwapFile *swap_file;
  310.   int       swap_num = 1;
  311.  
  312.   g_assert (initialize == FALSE);
  313.   swap_file = g_hash_table_lookup (swap_files, &swap_num);
  314.   g_assert (swap_file->fd == -1);
  315.   swap_file->fd = open (swap_file->filename,
  316.                   O_CREAT | O_RDWR | _O_BINARY | _O_TEMPORARY,
  317.             S_IREAD | S_IWRITE);
  318.   if (swap_file->fd != -1)
  319.     {
  320.       close (swap_file->fd);
  321.       swap_file->fd = -1;
  322.       unlink (swap_file->filename);
  323.       return TRUE;
  324.     }
  325.   return FALSE;
  326. }
  327.  
  328. static void
  329. tile_swap_init ()
  330. {
  331.  
  332.   if (initialize)
  333.     {
  334.       initialize = FALSE;
  335.  
  336.       swap_files = g_hash_table_new ((GHashFunc) tile_swap_hash,
  337.                      (GCompareFunc) tile_swap_compare);
  338.  
  339. #ifdef NOTDEF /* USE_PTHREADS */
  340.       pthread_create (&swapin_thread, NULL, &tile_swap_in_thread, NULL);
  341. #endif
  342.     }
  343. }
  344.  
  345. static guint
  346. tile_swap_hash (int *key)
  347. {
  348.   return ((guint) *key);
  349. }
  350.  
  351. static gint
  352. tile_swap_compare (int *a,
  353.            int *b)
  354. {
  355.   return (*a == *b);
  356. }
  357.  
  358. static void
  359. tile_swap_command (Tile *tile,
  360.            int   command)
  361. {
  362.   SwapFile *swap_file;
  363. #ifdef USE_PTHREADS
  364.   pthread_mutex_lock(&swapfile_mutex);
  365. #endif
  366.  
  367.   if (initialize)
  368.     tile_swap_init ();
  369.  
  370.   do {
  371.     swap_file = g_hash_table_lookup (swap_files, &tile->swap_num);
  372.     if (!swap_file)
  373.       {
  374.     g_warning ("could not find swap file for tile");
  375.     goto out;
  376.       }
  377.  
  378.     if (swap_file->fd == -1)
  379.       {
  380.     tile_swap_open (swap_file);
  381.  
  382.     if (swap_file->fd == -1)
  383.       goto out;
  384.       }
  385.   } while ((* swap_file->swap_func) (swap_file->fd, tile, command, swap_file->user_data));
  386. out:
  387. #ifdef USE_PTHREADS
  388.   pthread_mutex_unlock(&swapfile_mutex);
  389. #endif
  390.   return;
  391. }
  392.  
  393. static void
  394. tile_swap_open (SwapFile *swap_file)
  395. {
  396.   SwapFile *tmp;
  397.  
  398.   if (swap_file->fd != -1)
  399.     return;
  400.  
  401.   if (nopen_swap_files == MAX_OPEN_SWAP_FILES)
  402.     {
  403.       tmp = open_swap_files->data;
  404.       close (tmp->fd);
  405.       tmp->fd = -1;
  406.  
  407.       open_swap_files = g_list_remove (open_swap_files, open_swap_files->data);
  408.       nopen_swap_files -= 1;
  409.     }
  410.  
  411.   swap_file->fd = open (swap_file->filename,
  412.                   O_CREAT | O_RDWR | _O_BINARY | _O_TEMPORARY,
  413.             S_IREAD | S_IWRITE);
  414.  
  415.   if (swap_file->fd == -1)
  416.     {
  417.       g_message (_("Unable to open swap file.  The Gimp has run out of memory\n"
  418.                    "and cannot use the swap file.  Some parts of your images\n"
  419.                    "may be corrupted.  Try to save your work using different\n"
  420.                    "filenames, exit the Gimp and check the location of the\n"
  421.                    "swap directory in your Preferences."));
  422.       return;
  423.     }
  424.  
  425.   open_swap_files = g_list_append (open_swap_files, swap_file);
  426.   nopen_swap_files += 1;
  427. }
  428.  
  429. /* The actual swap file code. The swap file consists of tiles
  430.  *  which have been moved out to disk in order to conserve memory.
  431.  *  The swap file format is free form. Any tile in memory may
  432.  *  end up anywhere on disk.
  433.  * An actual tile in the swap file consists only of the tile data.
  434.  *  The offset of the tile on disk is stored in the tile data structure
  435.  *  in memory.
  436.  */
  437.  
  438. static int
  439. tile_swap_default (int       fd,
  440.            Tile     *tile,
  441.            int       cmd,
  442.            gpointer  user_data)
  443. {
  444.   DefSwapFile *def_swap_file;
  445.  
  446.   def_swap_file = (DefSwapFile*) user_data;
  447.  
  448.   switch (cmd)
  449.     {
  450.     case SWAP_IN:
  451.       tile_swap_default_in (def_swap_file, fd, tile);
  452.       break;
  453.     case SWAP_IN_ASYNC:
  454.       tile_swap_default_in_async (def_swap_file, fd, tile);
  455.       break;
  456.     case SWAP_OUT:
  457.       tile_swap_default_out (def_swap_file, fd, tile);
  458.       break;
  459.     case SWAP_DELETE:
  460.       tile_swap_default_delete (def_swap_file, fd, tile);
  461.       break;
  462.     case SWAP_COMPRESS:
  463.       g_warning ("tile_swap_default: SWAP_COMPRESS: UNFINISHED");
  464.       break;
  465.     }
  466.  
  467.   return FALSE;
  468. }
  469.  
  470. static void
  471. tile_swap_default_in_async (DefSwapFile *def_swap_file,
  472.                     int          fd,
  473.                     Tile        *tile)
  474. {
  475. #ifdef NOTDEF /* USE_PTHREADS */
  476.   AsyncSwapArgs *args;
  477.  
  478.   args = g_new(AsyncSwapArgs, 1);
  479.   args->def_swap_file = def_swap_file;
  480.   args->fd = fd;
  481.   args->tile = tile;
  482.  
  483.   /* add this tile to the list of tiles for the async swapin task */
  484.   pthread_mutex_lock (&async_swapin_mutex);
  485.   g_slist_append (async_swapin_tiles_end, args);
  486.  
  487.   if (!async_swapin_tiles)
  488.     async_swapin_tiles = async_swapin_tiles_end;
  489.   
  490.   pthread_cond_signal (&async_swapin_signal);
  491.   pthread_mutex_unlock (&async_swapin_mutex);
  492.  
  493. #else
  494.   /* ignore; it's only a hint anyway */
  495.   /* this could be changed to call out to another program that
  496.    * tries to make the OS read the data in from disk.
  497.    */
  498. #endif
  499.  
  500.   return;
  501. }
  502.  
  503. /* NOTE: if you change this function, check to see if your changes
  504.  * apply to tile_swap_in_attempt() near the end of the file.  The
  505.  * difference is that this version makes guarantees about what it
  506.  * provides, but tile_swap_in_attempt() just tries and gives up if
  507.  * anything goes wrong.
  508.  *
  509.  * I'm not sure that it is worthwhile to try to pull out common
  510.  * bits; I think the two functions are (at least for now) different
  511.  * enough to keep as two functions.
  512.  *
  513.  * N.B. the mutex on the tile must already have been locked on entry
  514.  * to this function.  DO NOT LOCK IT HERE.
  515.  */
  516. static void
  517. tile_swap_default_in (DefSwapFile *def_swap_file,
  518.               int          fd,
  519.               Tile        *tile)
  520. {
  521.   int bytes;
  522.   int err;
  523.   int nleft;
  524.   off_t offset;
  525.  
  526.   err = -1;
  527.  
  528.   if (tile->data)
  529.     {
  530.       return;
  531.     }
  532.  
  533.   if (def_swap_file->cur_position != tile->swap_offset)
  534.     {
  535.       def_swap_file->cur_position = tile->swap_offset;
  536.  
  537.       offset = lseek (fd, tile->swap_offset, SEEK_SET);
  538.       if (offset == -1)
  539.     {
  540.       if (seek_err_msg)
  541.         g_message ("unable to seek to tile location on disk: %d", err);
  542.       seek_err_msg = FALSE;
  543.       return;
  544.     }
  545.     }
  546.  
  547.   bytes = tile_size (tile);
  548.   tile_alloc (tile);
  549.  
  550.   nleft = bytes;
  551.   while (nleft > 0)
  552.     {
  553.       do {
  554.     err = read (fd, tile->data + bytes - nleft, nleft);
  555.       } while ((err == -1) && ((errno == EAGAIN) || (errno == EINTR)));
  556.  
  557.       if (err <= 0)
  558.     {
  559.       if (read_err_msg)
  560.         g_message ("unable to read tile data from disk: %d/%d ( %d ) bytes read", err, errno, nleft);
  561.       read_err_msg = FALSE;
  562.       return;
  563.     }
  564.  
  565.       nleft -= err;
  566.     }
  567.  
  568.   def_swap_file->cur_position += bytes;
  569.  
  570.   /*  Do not delete the swap from the file  */
  571.   /*  tile_swap_default_delete (def_swap_file, fd, tile);  */
  572.  
  573.   read_err_msg = seek_err_msg = TRUE;
  574. }
  575.  
  576. static void
  577. tile_swap_default_out (DefSwapFile *def_swap_file,
  578.                int          fd,
  579.                Tile        *tile)
  580. {
  581.   int bytes;
  582.   int rbytes;
  583.   int err;
  584.   int nleft;
  585.   off_t offset;
  586.  
  587.   off_t newpos;
  588.  
  589.   bytes = TILE_WIDTH * TILE_HEIGHT * tile->bpp;
  590.   rbytes = tile_size (tile);
  591.  
  592.   /*  If there is already a valid swap_offset, use it  */
  593.   if (tile->swap_offset == -1)
  594.     newpos = tile_swap_find_offset (def_swap_file, fd, bytes);
  595.   else 
  596.     newpos = tile->swap_offset;
  597.  
  598.   if (def_swap_file->cur_position != newpos)
  599.     {
  600.       offset = lseek (fd, newpos, SEEK_SET);
  601.       if (offset == -1)
  602.     {
  603.       if (seek_err_msg)
  604.         g_message ("unable to seek to tile location on disk: %d", errno);
  605.       seek_err_msg = FALSE;
  606.       return;
  607.     }
  608.       def_swap_file->cur_position = newpos;
  609.     }
  610.  
  611.   nleft = rbytes;
  612.   while (nleft > 0)
  613.     {
  614.       err = write (fd, tile->data + rbytes - nleft, nleft);
  615.       if (err <= 0)
  616.     {
  617.       if (write_err_msg)
  618.         g_message ("unable to write tile data to disk: %d ( %d ) bytes written", err, nleft);
  619.       write_err_msg = FALSE;
  620.       return;
  621.     }
  622.  
  623.       nleft -= err;
  624.     }
  625.  
  626.   def_swap_file->cur_position += rbytes;
  627.  
  628.   /* Do NOT free tile->data because we may be pre-swapping.
  629.    * tile->data is freed in tile_cache_zorch_next
  630.    */
  631.   tile->dirty = FALSE;
  632.   tile->swap_offset = newpos;
  633.  
  634.   write_err_msg = seek_err_msg = TRUE;
  635. }
  636.  
  637. static void
  638. tile_swap_default_delete (DefSwapFile *def_swap_file,
  639.               int          fd,
  640.               Tile        *tile)
  641. {
  642.   GList *tmp;
  643.   GList *tmp2;
  644.   Gap *gap;
  645.   Gap *gap2;
  646.   long start;
  647.   long end;
  648.  
  649.   if (tile->swap_offset == -1)
  650.     return;
  651.  
  652.   start = tile->swap_offset;
  653.   end = start + TILE_WIDTH * TILE_HEIGHT * tile->bpp;
  654.   tile->swap_offset = -1;
  655.  
  656.   tmp = def_swap_file->gaps;
  657.   while (tmp)
  658.     {
  659.       gap = tmp->data;
  660.  
  661.       if (end == gap->start)
  662.     {
  663.       gap->start = start;
  664.  
  665.       if (tmp->prev)
  666.         {
  667.           gap2 = tmp->prev->data;
  668.           if (gap->start == gap2->end)
  669.         {
  670.           gap2->end = gap->end;
  671.           tile_swap_gap_destroy (gap);
  672.           def_swap_file->gaps = g_list_remove_link (def_swap_file->gaps, tmp);
  673.           g_list_free (tmp);
  674.         }
  675.         }
  676.       break;
  677.     }
  678.       else if (start == gap->end)
  679.     {
  680.       gap->end = end;
  681.  
  682.       if (tmp->next)
  683.         {
  684.           gap2 = tmp->next->data;
  685.           if (gap->end == gap2->start)
  686.         {
  687.           gap2->start = gap->start;
  688.           tile_swap_gap_destroy (gap);
  689.           def_swap_file->gaps = g_list_remove_link (def_swap_file->gaps, tmp);
  690.           g_list_free (tmp);
  691.         }
  692.         }
  693.       break;
  694.     }
  695.       else if (end < gap->start)
  696.     {
  697.       gap = tile_swap_gap_new (start, end);
  698.  
  699.       tmp2 = g_list_alloc ();
  700.       tmp2->data = gap;
  701.       tmp2->next = tmp;
  702.       tmp2->prev = tmp->prev;
  703.       if (tmp->prev)
  704.         tmp->prev->next = tmp2;
  705.       tmp->prev = tmp2;
  706.  
  707.       if (tmp == def_swap_file->gaps)
  708.         def_swap_file->gaps = tmp2;
  709.       break;
  710.     }
  711.       else if (!tmp->next)
  712.     {
  713.       gap = tile_swap_gap_new (start, end);
  714.       tmp->next = g_list_alloc ();
  715.       tmp->next->data = gap;
  716.       tmp->next->prev = tmp;
  717.       break;
  718.     }
  719.  
  720.       tmp = tmp->next;
  721.     }
  722.  
  723.   if (!def_swap_file->gaps)
  724.     {
  725.       gap = tile_swap_gap_new (start, end);
  726.       def_swap_file->gaps = g_list_append (def_swap_file->gaps, gap);
  727.     }
  728.  
  729.   tmp = g_list_last (def_swap_file->gaps);
  730.   gap = tmp->data;
  731.  
  732.   if (gap->end == def_swap_file->swap_file_end)
  733.     {
  734.       tile_swap_resize (def_swap_file, fd, gap->start);
  735.       tile_swap_gap_destroy (gap);
  736.       def_swap_file->gaps = g_list_remove_link (def_swap_file->gaps, tmp);
  737.       g_list_free (tmp);
  738.     }
  739. }
  740.  
  741. static void
  742. tile_swap_resize (DefSwapFile *def_swap_file,
  743.           int          fd,
  744.           long         new_size)
  745. {
  746.   if (def_swap_file->swap_file_end > new_size)
  747.     {
  748.       ftruncate (fd, new_size);
  749.       /*fprintf(stderr, "TRUNCATED SWAP from %d to %d bytes.\n",
  750.     (int)def_swap_file->swap_file_end, (int) new_size);*/
  751.     }
  752.   def_swap_file->swap_file_end = new_size;
  753. }
  754.  
  755. static long
  756. tile_swap_find_offset (DefSwapFile *def_swap_file,
  757.                int          fd,
  758.                int          bytes)
  759. {
  760.   GList *tmp;
  761.   Gap *gap;
  762.   long offset;
  763.  
  764.   tmp = def_swap_file->gaps;
  765.   while (tmp)
  766.     {
  767.       gap = tmp->data;
  768.  
  769.       if ((gap->end - gap->start) >= bytes)
  770.     {
  771.       offset = gap->start;
  772.       gap->start += bytes;
  773.  
  774.       if (gap->start == gap->end)
  775.         {
  776.           tile_swap_gap_destroy (gap);
  777.           def_swap_file->gaps = g_list_remove_link (def_swap_file->gaps, tmp);
  778.           g_list_free (tmp);
  779.         }
  780.  
  781.       return offset;
  782.     }
  783.  
  784.       tmp = tmp->next;
  785.     }
  786.  
  787.   offset = def_swap_file->swap_file_end;
  788.  
  789.   tile_swap_resize (def_swap_file, fd, def_swap_file->swap_file_end + swap_file_grow);
  790.  
  791.   if ((offset + bytes) < (def_swap_file->swap_file_end))
  792.     {
  793.       gap = tile_swap_gap_new (offset + bytes, def_swap_file->swap_file_end);
  794.       def_swap_file->gaps = g_list_append (def_swap_file->gaps, gap);
  795.     }
  796.  
  797.   return offset;
  798. }
  799.  
  800. static Gap*
  801. tile_swap_gap_new (long start,
  802.            long end)
  803. {
  804.   Gap *gap;
  805.  
  806.   gap = g_new (Gap, 1);
  807.   gap->start = start;
  808.   gap->end = end;
  809.  
  810.   return gap;
  811. }
  812.  
  813. static void
  814. tile_swap_gap_destroy (Gap *gap)
  815. {
  816.   g_free (gap);
  817. }
  818.  
  819.  
  820. #ifdef NOTDEF /* USE_PTHREADS */
  821. /* go through the list of tiles that are likely to be used soon and
  822.  * try to swap them in.  If any tile is not in a state to be swapped
  823.  * in, ignore it, and the error will get dealt with when the tile
  824.  * is really needed -- assuming that the error still happens.
  825.  *
  826.  * Potential future enhancement: for non-threaded systems, we could
  827.  * fork() a process which merely attempts to bring tiles into the
  828.  * OS's buffer/page cache, where they will be read into the gimp
  829.  * more quickly.  This would be pretty trivial, actually.
  830.  */
  831.  
  832. static void
  833. tile_swap_in_attempt (DefSwapFile *def_swap_file,
  834.               int          fd,
  835.               Tile        *tile)
  836. {
  837.   int bytes;
  838.   int err;
  839.   int nleft;
  840.   off_t offset;
  841.  
  842.   err = -1;
  843.  
  844.   TILE_MUTEX_LOCK (tile);
  845.   if (tile->data)
  846.     goto out;
  847.  
  848.   if (!tile->swap_num || !tile->swap_offset)
  849.     goto out;
  850.  
  851.   if (def_swap_file->cur_position != tile->swap_offset)
  852.     {
  853.       def_swap_file->cur_position = tile->swap_offset;
  854.  
  855.       offset = lseek (fd, tile->swap_offset, SEEK_SET);
  856.       if (offset == -1)
  857.     return;
  858.     }
  859.  
  860.   bytes = tile_size (tile);
  861.   tile_alloc (tile);
  862.  
  863.   nleft = bytes;
  864.   while (nleft > 0)
  865.     {
  866.       do {
  867.     err = read (fd, tile->data + bytes - nleft, nleft);
  868.       } while ((err == -1) && ((errno == EAGAIN) || (errno == EINTR)));
  869.  
  870.       if (err <= 0)
  871.         {
  872.       g_free (tile->data);
  873.       return;
  874.         }
  875.  
  876.       nleft -= err;
  877.     }
  878.  
  879.   def_swap_file->cur_position += bytes;
  880.  
  881. out:
  882.   TILE_MUTEX_UNLOCK (tile);
  883. }
  884.  
  885. static void *
  886. tile_swap_in_thread (void *data)
  887. {
  888.   AsyncSwapArgs *args;
  889.   GSList *free_item;
  890.  
  891.   while (1)
  892.     {
  893.       pthread_mutex_lock (&async_swapin_mutex);
  894.  
  895.       if (!async_swapin_tiles)
  896.         {
  897.           pthread_cond_wait (&async_swapin_signal, &async_swapin_mutex);
  898.         }
  899.       args = async_swapin_tiles->data;
  900.  
  901.       free_item = async_swapin_tiles;
  902.       async_swapin_tiles = async_swapin_tiles->next;
  903.       g_slist_free_1(free_item);
  904.       if (!async_swapin_tiles)
  905.         async_swapin_tiles_end = NULL;
  906.  
  907.       pthread_mutex_unlock (&async_swapin_mutex);
  908.  
  909.       tile_swap_in_attempt(args->def_swap_file, args->fd, args->tile);
  910.  
  911.       g_free(args);
  912.     }
  913. }
  914. #endif
  915.